package com.rizzo.analytics.domain.info;

import com.google.common.collect.Multimap;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
import com.google.common.collect.TreeMultimap;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.codehaus.jackson.annotate.JsonIgnore;

import java.io.Serializable;
import java.util.Collection;
import java.util.Map;
import java.util.Set;

public class Info implements Serializable {

    private static final long serialVersionUID = 5L;

    private Multimap<String, Instance> performanceData;

    private Multimap<String, String> cacheData;

    private Multimap<String, Long> notificationData;

    private Set<String> quotaData;

    private Set<String> errorCodes;

    public Info() {
    }

    public Multimap<String, Instance> performanceData() {
        if (this.performanceData == null) {
            this.performanceData = TreeMultimap.create();
        }
        return performanceData;
    }

    public Map<String, Collection<Instance>> getPerformance() {
        if (this.performanceData == null) {
            this.performanceData = TreeMultimap.create(Ordering.natural(), Ordering.natural());
        }
        return this.performanceData.asMap();
    }

    public void setPerformance(Map<String, Collection<Instance>> performances) {
        for (Map.Entry<String, Collection<Instance>> stringCollectionEntry : performances.entrySet()) {
            for (Instance instance : stringCollectionEntry.getValue()) {
                performanceData().put(stringCollectionEntry.getKey(), instance);
            }
        }
    }

    public Multimap<String, String> cacheData() {
        if (this.cacheData == null) {
            this.cacheData = TreeMultimap.create(Ordering.natural(), Ordering.natural());
        }
        return cacheData;
    }

    public Map<String, Collection<String>> getCaches() {
        if (this.cacheData == null) {
            this.cacheData = TreeMultimap.create(Ordering.natural(), Ordering.natural());
        }
        return this.cacheData.asMap();
    }

    public void setCaches(Map<String, Collection<String>> caches) {
        for (Map.Entry<String, Collection<String>> stringCollectionEntry : caches.entrySet()) {
            for (String string : stringCollectionEntry.getValue()) {
                cacheData().put(stringCollectionEntry.getKey(), string);
            }
        }
    }

    public Multimap<String, Long> notificationData() {
        if (this.notificationData == null) {
            this.notificationData = TreeMultimap.create();
        }
        return notificationData;
    }

    public Map<String, Collection<Long>> getNotifications() {
        if (this.notificationData == null) {
            this.notificationData = TreeMultimap.create(Ordering.natural(), Ordering.natural());
        }
        return this.notificationData.asMap();
    }

    public void setNotifications(Map<String, Collection<Long>> notifications) {
        for (Map.Entry<String, Collection<Long>> stringCollectionEntry : notifications.entrySet()) {
            for (Long id : stringCollectionEntry.getValue()) {
                notificationData().put(stringCollectionEntry.getKey(), id);
            }
        }
    }

    public Set<String> getQuotaData() {
        if (this.quotaData == null) {
            this.quotaData = Sets.newTreeSet(Ordering.natural());
        }
        return quotaData;
    }

    public void setQuotaData(Set<String> quotaData) {
        this.quotaData = quotaData;
    }

    public void addQuota(String quota) {
        if (this.quotaData == null) {
            this.quotaData = Sets.newTreeSet(Ordering.natural());
        }
        this.quotaData.add(quota);
    }

    public Set<String> getErrorCodes() {
        if (this.errorCodes == null) {
            this.errorCodes = Sets.newTreeSet(Ordering.natural());
        }
        return errorCodes;
    }

    public void setErrorCodes(Set<String> errorCodes) {
        this.errorCodes = errorCodes;
    }

    public void addErrorCode(String code) {
        if (this.errorCodes == null) {
            this.errorCodes = Sets.newTreeSet(Ordering.natural());
        }
        this.errorCodes.add(code);
    }

    public void merge(Info updateInfo) {
        if (updateInfo.cacheData() != null) {
            this.cacheData().putAll(updateInfo.cacheData());
        }
        if (updateInfo.performanceData() != null) {
            this.performanceData().putAll(updateInfo.performanceData());
        }
        if (updateInfo.notificationData() != null) {
            this.notificationData().putAll(updateInfo.notificationData());
        }
        if (updateInfo.getQuotaData() != null) {
            this.getQuotaData().addAll(updateInfo.getQuotaData());
        }
        if (updateInfo.getErrorCodes() != null) {
            this.getErrorCodes().addAll(updateInfo.getErrorCodes());
        }
    }

    @JsonIgnore
    public boolean isEmpty() {
        return getNotifications().isEmpty() && getCaches().isEmpty() && getErrorCodes().isEmpty() && getQuotaData().isEmpty() && getPerformance().isEmpty();
    }

    @Override
    public boolean equals(Object o) {
        return EqualsBuilder.reflectionEquals(this, o);
    }

    @Override
    public int hashCode() {
        return HashCodeBuilder.reflectionHashCode(this);
    }

}
